Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 | /** * Error Comments API * * GET /api/admin/monitoring/errors/[fingerprint]/comments * Returns paginated comments for an error. * * POST /api/admin/monitoring/errors/[fingerprint]/comments * Adds a new comment to an error. */ export const dynamic = 'force-dynamic'; import { NextRequest, NextResponse } from 'next/server'; import { prisma } from '@/lib/prisma'; import { withAdmin, withErrorHandling, successResponse, errorResponse, type ApiSuccessResponse, type ApiErrorResponse, type AuthenticatedUser, } from '@/lib/api'; import type { ErrorComment } from '@prisma/client'; import type { Session } from 'next-auth'; /** * Comments list response */ interface CommentsListResponse { comments: ErrorComment[]; total: number; } /** * GET handler - List comments for an error */ async function handleGet( request: NextRequest, context: { params?: Promise<Record<string, string>> } | undefined, // eslint-disable-next-line @typescript-eslint/no-unused-vars _session: Session, // eslint-disable-next-line @typescript-eslint/no-unused-vars _user: AuthenticatedUser ): Promise<NextResponse<ApiSuccessResponse<CommentsListResponse> | ApiErrorResponse>> { const params = await context?.params; const fingerprint = params?.fingerprint; if (!fingerprint) { return errorResponse('INVALID_PARAM', 'Fingerprint is required', { status: 400 }); } const { searchParams } = new URL(request.url); const limit = Math.min(100, Math.max(1, parseInt(searchParams.get('limit') || '50', 10))); const offset = Math.max(0, parseInt(searchParams.get('offset') || '0', 10)); // Find the error statistic const errorStat = await prisma.errorStatistic.findUnique({ where: { fingerprint }, select: { id: true }, }); if (!errorStat) { return errorResponse('NOT_FOUND', 'Error not found', { status: 404 }); } const [comments, total] = await Promise.all([ prisma.errorComment.findMany({ where: { errorStatId: errorStat.id }, orderBy: { createdAt: 'desc' }, skip: offset, take: limit, }), prisma.errorComment.count({ where: { errorStatId: errorStat.id }, }), ]); return successResponse({ comments, total }); } /** * POST handler - Add a comment to an error */ async function handlePost( request: NextRequest, context: { params?: Promise<Record<string, string>> } | undefined, session: Session, user: AuthenticatedUser ): Promise<NextResponse<ApiSuccessResponse<{ comment: ErrorComment }> | ApiErrorResponse>> { const params = await context?.params; const fingerprint = params?.fingerprint; if (!fingerprint) { return errorResponse('INVALID_PARAM', 'Fingerprint is required', { status: 400 }); } const body = await request.json(); const { content } = body; if (!content?.trim()) { return errorResponse('INVALID_PARAM', 'Comment content is required', { status: 400 }); } // Find the error statistic const errorStat = await prisma.errorStatistic.findUnique({ where: { fingerprint }, select: { id: true }, }); if (!errorStat) { return errorResponse('NOT_FOUND', 'Error not found', { status: 404 }); } // Use authenticated user data from withAdmin middleware const userId = user.id; const userEmail = user.email; // Create comment and history entry in transaction const [comment] = await prisma.$transaction([ prisma.errorComment.create({ data: { errorStatId: errorStat.id, userId, userEmail, content: content.trim(), }, }), prisma.errorHistory.create({ data: { errorStatId: errorStat.id, userId, userEmail, action: 'COMMENTED', }, }), ]); return successResponse({ comment }); } export const GET = withErrorHandling(withAdmin(handleGet)); export const POST = withErrorHandling(withAdmin(handlePost)); |